/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2019-2019.
 * Description: add user exception feature support
 * Author: zhoumansuo <zhoumansuo@huawei.com>
 * Create: 2019-01-11
 */

#ifndef __USR_EXCEPT_H__
#define __USR_EXCEPT_H__

#ifdef CONFIG_RTOS_HAL_SRE_PREHANDLER
#include <asm/system_misc.h>
#include <linux/task_struct_extend.h>

DECLARE_PER_CPU(struct usr_except_args, usr_except_args);
static inline int sre_do_usr_exception(void)
{
	struct rtos_task_struct *rtos_task = task_to_rtos_task(current);
	struct usr_except_args *ptr_args = &get_cpu_var(usr_except_args);
	int ret = SRE_UEXCEPT_BYPASS;

	if ((rtos_task->sre_prehandler != NULL) && (user_mode(ptr_args->sp))) {
		char *except_desc = except_desc_array[ptr_args->except_type];

		printk("%s pid=%d: %s\n handle by sre prehandler",
			current->comm, task_pid_nr(current), except_desc);
#ifdef CONFIG_RTOS_HAL_SRE_DEBUG_NEON
		fpsimd_preserve_current_state();
#endif
		ret = rtos_task->sre_prehandler(ptr_args);
		if (!(ret == SRE_UEXCEPT_CAN_HANDLE)) {
			printk(KERN_ERR "sre_prehandler return unknown %d\n", ret);
			ret = SRE_UEXCEPT_BYPASS;
		} else {
			printk(KERN_ERR "sre_prehandler return %d\n", ret);
		}
	}
	put_cpu_var(usr_except_args);
	return ret;
}

static inline struct usr_except_args *sre_set_except_args(unsigned int except_type,
													unsigned long addr,
													unsigned int esr,
													struct pt_regs *regs)
{
	struct usr_except_args *ptr_args = &get_cpu_var(usr_except_args);

	ptr_args->except_type = except_type;
	ptr_args->addr = addr;
#ifdef CONFIG_ARM64
	ptr_args->esr = esr;
#endif
#ifdef CONFIG_ARM
	ptr_args->fsr = esr;
#endif
	ptr_args->sp = regs;
	put_cpu_var(usr_except_args);
	return ptr_args;
}

#endif
#endif
